package org.amos.core.frame.tool.log;

import ch.qos.logback.classic.Level;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.amos.core.basic.annotation.Log;
import org.amos.core.basic.utils.HttpUtils;
import org.amos.core.basic.utils.JsonUtils;
import org.amos.core.frame.aspect.AopManager;
import org.amos.core.frame.utils.ReflectUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

/**
 * @desc: 日志切面抽象类
 * @author: liubt
 * @date: 2022-08-11 11:14
 **/
@Slf4j
public abstract class AbstractOperateLog implements InitializingBean {
    @Autowired(required = false)
    private AopManager aopManager;
    /**
     * 是否记录切面日志
     */
    @Value("${amos.log.show-default-log:true}")
    protected boolean showDefaultLog;

    /**
     * 排除的路径
     */
    @Value("${amos.log.exclude-urls:[]}")
    protected List<String> excludeUrls;

    /**
     * 执行业务方法
     *
     * @param log
     * @param clazz
     * @param method
     * @param args
     * @param resultInfo
     * @param time       执行耗时 ms
     * @throws Throwable
     */
    protected void doService(Log log, Class<?> clazz, Method method, Object[] args, String resultInfo, String level, Long time) throws Throwable {
        // 如果请求路径被排除，则放行
        if (StrUtil.startWithAny(HttpUtils.getURI(), excludeUrls.toArray(new String[]{}))) {
            return;
        }

        if (showDefaultLog) {
            doPrint(log, clazz, method, args, resultInfo, level, time);
        } else {
            doCustom(log, clazz, method, args, resultInfo, level, time);
        }
    }

    /**
     * 通用日志打印方法
     *
     * @param log
     * @param clazz
     * @param method
     * @param args
     * @param resultInfo
     * @param level
     * @param time       执行耗时 ms
     * @return
     * @throws Throwable
     */
    protected void doPrint(Log log, Class<?> clazz, Method method, Object[] args, String resultInfo, String level, Long time)
            throws Throwable {

        String consoleStr = StrBuilder.create()
                .append("\n=========================begin record=========================\n")
                .append("request desc   =>  ").append(log.value()).append("\n")
                .append("request url    =>  ").append(StrUtil.blankToDefault(HttpUtils.getURI(), clazz.getName())).append("\n")
                .append("request method =>  ").append(clazz.getName()).append(".").append(method.getName()).append("\n")
                .append("request params =>  ").append(JsonUtils.objectToJson(ReflectUtils.getParamsMap(method, args))).append("\n")
                .append("request result =>  ").append(resultInfo).append("\n")
                .append("execute time   =>  ").append(String.valueOf(time)).append("ms \n")
                .append("=========================end   record=========================\n")
                .toString();

        if (Level.INFO.levelStr.equals(level)) {
            AbstractOperateLog.log.info(consoleStr);
        }
        if (Level.ERROR.levelStr.equals(level)) {
            AbstractOperateLog.log.error(consoleStr);
        }

        doCustom(log, clazz, method, args, resultInfo, level, time);
    }

    /**
     * 调用自定义切面处理方法
     *
     * @param log
     * @param clazz
     * @param method
     * @param args
     * @param resultInfo 返回结果
     * @param level
     * @param time       执行耗时 ms
     * @throws Throwable
     */
    protected void doCustom(Log log, Class<?> clazz, Method method, Object[] args, String resultInfo, String level, Long time) throws Throwable {
        if (Objects.nonNull(aopManager)) {
            aopManager.doCustom(log, clazz, method, args, resultInfo, level, time);
        }
    }

}
